import os
import redis
from redis.connection import ConnectionPool
from utils.logger import get_logger, error, info, debug

# 创建Redis操作专用的日志器
logger = get_logger("redis", daily_rotation=True, level="INFO")

# Redis连接池对象
_pool = None


def init_redis_pool(host='localhost', port=6379, password=None, db=0,
                  max_connections=10, socket_timeout=None, decode_responses=True):
    """
    初始化Redis连接池
    
    Args:
        host: Redis主机地址
        port: Redis端口
        password: Redis密码
        db: 数据库编号
        max_connections: 最大连接数
        socket_timeout: 连接超时时间
        decode_responses: 是否自动解码响应
        
    Returns:
        ConnectionPool: Redis连接池对象
    """
    global _pool
    try:
        if _pool is None:
            _pool = ConnectionPool(
                host=host,
                port=port,
                password=password,
                db=db,
                max_connections=max_connections,
                socket_timeout=socket_timeout,
                decode_responses=decode_responses
            )
            logger.info(f"Redis连接池初始化成功，地址: {host}:{port}, 数据库: {db}")
        return _pool
    except Exception as e:
        error(f"初始化Redis连接池失败: {str(e)}", exc_info=True)
        raise


def get_redis_connection():
    """
    从连接池获取Redis连接
    
    Returns:
        Redis: Redis连接对象
    """
    global _pool
    if _pool is None:
        # 如果连接池未初始化，使用默认参数初始化
        init_redis_pool()
    try:
        conn = redis.Redis(connection_pool=_pool)
        logger.debug("从连接池获取Redis连接成功")
        return conn
    except Exception as e:
        error(f"从连接池获取Redis连接失败: {str(e)}", exc_info=True)
        raise


# 以下是一些常用的Redis操作封装

def set_value(key, value, ex=None):
    """
    设置字符串键值
    
    Args:
        key: 键名
        value: 值
        ex: 过期时间（秒）
        
    Returns:
        bool: 是否成功
    """
    try:
        conn = get_redis_connection()
        result = conn.set(key, value, ex=ex)
        debug(f"设置Redis键值成功: {key}")
        return result
    except Exception as e:
        error(f"设置Redis键值失败: {key}, 错误: {str(e)}", exc_info=True)
        raise


def get_value(key):
    """
    获取字符串键值
    
    Args:
        key: 键名
        
    Returns:
        str: 键值，不存在返回None
    """
    try:
        conn = get_redis_connection()
        value = conn.get(key)
        debug(f"获取Redis键值成功: {key}")
        return value
    except Exception as e:
        error(f"获取Redis键值失败: {key}, 错误: {str(e)}", exc_info=True)
        raise


def delete_key(key):
    """
    删除键
    
    Args:
        key: 键名
        
    Returns:
        int: 删除的键数量
    """
    try:
        conn = get_redis_connection()
        result = conn.delete(key)
        debug(f"删除Redis键成功: {key}")
        return result
    except Exception as e:
        error(f"删除Redis键失败: {key}, 错误: {str(e)}", exc_info=True)
        raise


def hash_set(name, key, value):
    """
    设置哈希表字段值
    
    Args:
        name: 哈希表名
        key: 字段名
        value: 字段值
        
    Returns:
        int: 1表示新字段被设置，0表示字段被更新
    """
    try:
        conn = get_redis_connection()
        result = conn.hset(name, key, value)
        debug(f"设置Redis哈希字段成功: {name}.{key}")
        return result
    except Exception as e:
        error(f"设置Redis哈希字段失败: {name}.{key}, 错误: {str(e)}", exc_info=True)
        raise


def hash_get(name, key):
    """
    获取哈希表字段值
    
    Args:
        name: 哈希表名
        key: 字段名
        
    Returns:
        str: 字段值，不存在返回None
    """
    try:
        conn = get_redis_connection()
        value = conn.hget(name, key)
        logger.debug(f"获取Redis哈希字段成功: {name}.{key}")
        return value
    except Exception as e:
        logger.error(f"获取Redis哈希字段失败: {name}.{key}, 错误: {str(e)}", exc_info=True)
        raise


def hash_getall(name):
    """
    获取哈希表所有字段和值
    
    Args:
        name: 哈希表名
        
    Returns:
        dict: 包含所有字段和值的字典
    """
    try:
        conn = get_redis_connection()
        result = conn.hgetall(name)
        debug(f"获取Redis哈希表所有字段成功: {name}")
        return result
    except Exception as e:
        error(f"获取Redis哈希表所有字段失败: {name}, 错误: {str(e)}", exc_info=True)
        raise


def list_push(name, *values):
    """
    将一个或多个值推入列表的右端
    
    Args:
        name: 列表名
        values: 一个或多个值
        
    Returns:
        int: 操作后列表的长度
    """
    try:
        conn = get_redis_connection()
        result = conn.rpush(name, *values)
        debug(f"向Redis列表推入值成功: {name}")
        return result
    except Exception as e:
        error(f"向Redis列表推入值失败: {name}, 错误: {str(e)}", exc_info=True)
        raise


def list_range(name, start=0, end=-1):
    """
    获取列表指定范围内的元素
    
    Args:
        name: 列表名
        start: 开始索引
        end: 结束索引，-1表示最后一个元素
        
    Returns:
        list: 元素列表
    """
    try:
        conn = get_redis_connection()
        result = conn.lrange(name, start, end)
        debug(f"获取Redis列表范围成功: {name}[{start}:{end}]")
        return result
    except Exception as e:
        error(f"获取Redis列表范围失败: {name}, 错误: {str(e)}", exc_info=True)
        raise


def close_redis_pool():
    """
    关闭Redis连接池
    """
    global _pool
    if _pool is not None:
        # 在redis的ConnectionPool中没有直接的关闭方法
        # 但我们可以将连接池对象设为None，让Python的垃圾回收机制处理
        _pool = None
        info("Redis连接池已关闭")